﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Diagnostics;
using System.Linq;
using System.Text;
using CommonServices;
using ContribServices;
using AutoClick.WPFHelpers;

namespace AutoClick.Algorithms
{
    /// <summary>
    /// Algorithm which lauch a click if the pointer is in the radius, even if this pointer quits the 
    /// radius between two periods of potential auto-click
    /// </summary>
    public class AlgorithmClickIfPointerIsInRadius : AutoClickAlgorithmBase, IAutoClickAlgorithm
    {
        #region Variables
        private string _typeOfClick;
        private int _countNumberOfTicks;
        private int _radius;
        private int _countNumberOfCommonTimerTicks;
        private int _areaOfReferenceClickRadius;
        private int _commonTimerMultiple;
        private double _distanceFromReference;
        private bool _clickInProcess;
        private AutoClickCircleControl _autoClickCircleControl;
        private ICommonTimer _timer;
        private IPointerDeviceDriver _pointerDeviceDriver;
        private System.Drawing.Point _deltaPosition;
        private System.Drawing.Point _referencialPointerPosition;
        public Point ReferencialPointerPosition
        {
            get { return _referencialPointerPosition; }
            set { _referencialPointerPosition = value; }
        }
        public AutoClickCircleControl AutoClickCircleControl
        {
            get { return _autoClickCircleControl; }
            set { _autoClickCircleControl = value; }
        }
        public bool ClickInProcess
        {
            get { return _clickInProcess; }
            set { _clickInProcess = value; }
        }
        public int CountNumberOfCommonTimerTicks
        {
            get { return _countNumberOfCommonTimerTicks; }
            set { _countNumberOfCommonTimerTicks = value; }
        }
        public string TypeOfClick
        {
            get { return _typeOfClick; }
            set { _typeOfClick = value; }
        }
        public int AreaOfReferenceClickRadius
        {
            get { return _areaOfReferenceClickRadius; }
            set { _areaOfReferenceClickRadius = value; }
        }
        public int CommonTimerMultiple
        {
            get { return _commonTimerMultiple; }
            set { _commonTimerMultiple = value; }
        }
        #endregion

        #region Constructor
        public AlgorithmClickIfPointerIsInRadius(int commonTimerMultiple, int radius, ICommonTimer timer, IPointerDeviceDriver pointerDeviceDriver, string typeOfClick, AutoClickCircleControl autoClickCircleControl)
        {
            CommonTimerMultiple = commonTimerMultiple;
            AreaOfReferenceClickRadius = radius;
            TypeOfClick = "";
            TypeOfClick = typeOfClick;
            ClickInProcess = true;
            _pointerDeviceDriver = pointerDeviceDriver;
            ReferencialPointerPosition = new Point(_pointerDeviceDriver.CurrentPointerXLocation
                                                    , _pointerDeviceDriver.CurrentPointerYLocation);

            _timer = timer;
            _autoClickCircleControl = autoClickCircleControl;
        }
        #endregion

        #region Control of click
        /// <summary>
        /// Method called each time a Timer.Tick event is sent by the CommonTimer.
        /// Method that lauches ClickTick's method
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Timer_Tick(object sender, EventArgs e)
        {
            CountNumberOfCommonTimerTicks++;
            if (CountNumberOfCommonTimerTicks >= _commonTimerMultiple && TypeOfClick != "noClick")
            {
                Click_Tick();
                CountNumberOfCommonTimerTicks = 0;
            }
        }

        /// <summary>
        /// Method that :
        /// - Launches an autoclick if the specific conditions are OK
        /// - Sets a new referencial position if the specifics conditions are not OK
        /// - Controls the circle reference for click
        /// </summary>
        public void Click_Tick()
        {
            //Calculate the distance between the referencial mouse position and the actual mouse position
            _deltaPosition.X = Math.Abs(ReferencialPointerPosition.X - _pointerDeviceDriver.CurrentPointerXLocation);
            _deltaPosition.Y = Math.Abs(ReferencialPointerPosition.Y - _pointerDeviceDriver.CurrentPointerYLocation);
            _distanceFromReference = Math.Sqrt((int)Math.Pow(_deltaPosition.X, 2) + (int)Math.Pow(_deltaPosition.Y, 2));

            //Click if this is needed or calcuate the new referencial position and update the circle position
            if (_distanceFromReference <= AreaOfReferenceClickRadius && ClickInProcess)
            {
                LaunchClick(TypeOfClick, _pointerDeviceDriver);
                ClickInProcess = false;
            }
            if (_distanceFromReference > AreaOfReferenceClickRadius)
            {
                ReferencialPointerPosition = new Point(_pointerDeviceDriver.CurrentPointerXLocation
                                                        , _pointerDeviceDriver.CurrentPointerYLocation);
                ClickInProcess = true;
                _autoClickCircleControl.UpdateCirclePosition(ReferencialPointerPosition);
            }
        }
        #endregion

        #region IAutoClickAlgorithm Membres
        public void Start()
        {
            _timer.Tick += new EventHandler(Timer_Tick);
        }
        public void Stop()
        {
            _timer.Tick -= new EventHandler(Timer_Tick);
        }
        #endregion
    }
}
